package org.scboy.rbac.service.imp;

import java.util.Date;
import java.util.Locale;
import java.util.UUID;

import org.scboy.common.cache.SystemConfig;
import org.scboy.coobi.sql.factory.EntityFactory;
import org.scboy.rbac.dao.RbacLoginSessionDao;
import org.scboy.rbac.dao.RbacLoginStateDao;
import org.scboy.rbac.dao.RbacOrgDao;
import org.scboy.rbac.dao.RbacOrgUserDao;
import org.scboy.rbac.dao.RbacUserAccountDao;
import org.scboy.rbac.dao.RbacUserInfoDao;
import org.scboy.rbac.loads.loadLoginUser;
import org.scboy.rbac.service.LoginSessionService;
import org.scboy.utils.entitys.coobi.Model;
import org.scboy.utils.entitys.coobi.Page;
import org.scboy.utils.entitys.rbac.LoginUser;
import org.scboy.utils.enums.coobi.OrderType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.SM3;

/**
 * 登录回话信息
 * @author yanghao
 * 
 */
@Service
@EnableCaching
public class LoginSessionServiceImp implements LoginSessionService {

	@Autowired
	EntityFactory factory;

	@Autowired
	SystemConfig config;
	
	@Autowired
	loadLoginUser login;
	
	/**
	 * 分页查询登录回话信息
	 * @param model 查询参数
	 * @param limit 分页参数
	 * @return
	 */
	@Override
	public Page page(Model model){
		RbacLoginSessionDao dao=factory.getDao(RbacLoginSessionDao.class);
		model.orderBy("loginTimeStr",OrderType.DESC);
		return dao.page(model);
	}
	
	/**
	 * 用户登录 登录状态：0 ：在线，1：正常退出，2：重复登录，3：强制退出,4：回话过期
	 * @param loginSessionId
	 * @param account
	 * @param password
	 * @param ip
	 * @return
	 */
	@Override
	@Transactional
	public LoginUser login(String loginName,String password,String loginType,String ip,String ips){
		
		RbacLoginSessionDao dao=factory.getDao(RbacLoginSessionDao.class);
		RbacUserAccountDao accountDao=factory.getDao(RbacUserAccountDao.class);
		RbacUserInfoDao userDao=factory.getDao(RbacUserInfoDao.class);
		RbacOrgUserDao orgUserDao=factory.getDao(RbacOrgUserDao.class);
		RbacOrgDao orgDao=factory.getDao(RbacOrgDao.class);
		
		
		if(StrUtil.isEmpty(loginName))return null;
		//验证帐号是否存在
		Model accountModel=accountDao.get(new Model().add("loginAccount", loginName.trim().toUpperCase(Locale.ENGLISH)).add("loginType", loginType).add("loginState", 1));
		if(accountModel==null){
			return null;
		}else{
			//验证用户密码是否正确
			Model userModel=userDao.get(new Model().add("id", accountModel.getString("userId")).add("password",SM3.create().digestHex(password)).add("userState", 1));
			if(userModel==null){
				return null;
			}else{
				String userId=userModel.getString("id");
				Model orgUser=orgUserDao.get(Model.create().add("userId", userId));
				Model org=Model.create(); 
				if(orgUser!=null) {
					org=orgDao.get(Model.create().add("id", orgUser.getString("orgId")));
				}
				Date loginTime=new Date();
				Model loginSession=Model.create().add("id", UUID.randomUUID().toString())
						.add("userId", userId)
						.add("userName", userModel.getString("userName"))
						.add("loginName", accountModel.getString("loginAccount"))
						.add("loginIp", ip)
						.add("loginIps", ips)
						.add("sessionState", 0)
						.add("loginTime", loginTime)
						.add("loginTimeStr", DateUtil.format(loginTime, "yyyyMMddHHmmssSSS"))
						.add("lastTime",  new Date())
						.add("orgId", org.getString("id"))
						.add("orgName", org.getString("orgName"))
						.add("loginState", 0);
				//关闭旧的登陆回话状态。设为重复登录
				dao.update(
						Model.create().add("sessionState", 1)
						.add("loginOutTime", new Date())
						.add("loginState",2),
						Model.create().add("userId", userId)
						.add("sessionState", 0));
				//记录当前登陆状态。
				if(dao.insert(loginSession)>0){
					updateState(userId,loginSession.getString("id"), 0);
					//获取用户信息，并返回。
					return login.get(loginSession.getString("id"));
				}else{
					return null;
				}
			}
		}
	}
	
	
	@Override
	public boolean modifyAccess(String loginSessionId) {
		RbacLoginSessionDao dao=factory.getDao(RbacLoginSessionDao.class);
		int result=dao.update(Model.create().add("lastTime",  new Date()),Model.create().add("id", loginSessionId));
		if(result>0){
			return true;
		}else{
			return false;
		}
	}

	@Override
	@Transactional
	@CacheEvict(value="RBAC_LOGIN_CACHE",key="#loginSessionId")
	public boolean loginOut(String loginSessionId,int state){
		RbacLoginSessionDao dao=factory.getDao(RbacLoginSessionDao.class);
		updateState(dao.get(Model.create().add("id", loginSessionId)).getString("userId"),loginSessionId, 1);
		int result=dao.update(
				Model.create().add("sessionState", 1)
				.add("loginOutTime", new Date())
				.add("loginState",state),
				Model.create().add("id", loginSessionId));
		if(result>0){
			return true;
		}else{
			return false;
		}
	}
	
	@Override
	@Transactional
	@CacheEvict(value="RBAC_LOGIN_CACHE",key="#id")
	public boolean adminClose(String id) {
		RbacLoginSessionDao dao=factory.getDao(RbacLoginSessionDao.class);
		int result=dao.update(
				Model.create().add("sessionState", 1)
				.add("loginOutTime", new Date())
				.add("loginState",3),
				Model.create().add("id", id));
		Model loginSession=dao.get(Model.create().add("id", id));
		updateState(loginSession.getString("userId"),loginSession.getString("id"), 1);
		if(result>0){
			return true;
		}else{
			return false;
		}
	}

	@Override
	public boolean delete(Date date) {
		RbacLoginSessionDao dao=factory.getDao(RbacLoginSessionDao.class);
		int result=dao.delete(Model.create().LE("loginTime", date).add("sessionState", 1));
		if(result>0){
			return true;
		}else{
			return false;
		}
	}

	@Override
	public boolean updateState(String userId,String sessionId, int state) {
		RbacLoginStateDao dao=factory.getDao(RbacLoginStateDao.class);
		Model model=dao.get(Model.create().add("userId", userId));
		if(model==null){
			model=Model.create().add("userId", userId);
			model.add("loginTime", new Date());
			model.add("lastTime", new Date());
			if(StrUtil.isNotEmpty(sessionId)){
				model.add("sessionId",sessionId);
			}
			model.add("sessionState",state);
			dao.insert(model);
		}else{
			if(StrUtil.isNotEmpty(sessionId)){
				model.add("sessionId",sessionId);
			}
			model.add("loginTime", new Date());
			model.add("lastTime", new Date());
			model.add("sessionState",state);
			dao.update(model);
		}
		return true;
	}

	@Override
	public Model getState(String userId) {
		RbacLoginStateDao dao=factory.getDao(RbacLoginStateDao.class);
		return dao.get(Model.create().add("userId", userId));
	}
}
